package controller;

import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Observable;
import java.util.Observer;
import buttons.*;
import model.Turtle;
import model.TurtleModel;
import util.coordTranslate.AbstractCoordinateSystem;
import view.Frame;
import view.panels.HistoryList;
import view.panels.TurtleList;
import expressions.Expression;

/**
 * The controller mediates actions between the view and the model.
 * 
 * @author Nathan Klug
 */
public class TurtleController extends Controller implements Observer
{

    /*
     * The controller is linked to (and controls) the model and the view.
     */
    private HistoryList myHistory;
    private TurtleList myTurtles;
    private TurtleModel myModel;
    private Frame myView;

    /**
     * The default constructor instantiates a new model and a new view.
     */
    public TurtleController()
    {
        myModel = new TurtleModel(this);
        myView = new Frame(this);
        myView.setVisible(true);
    }

    /**
     * Parses the string and evaluates the resulting expression
     */
    public double parseAndEvaluate(String input)
    {
        // return evaluate(parse(s));
        // System.out.println(input);
        myView.addData(myView.getCanvas().getCurrentBackground(), myView
                .getCanvas().getCoordinates());
        Expression<Double> root = parse(input);
        updateHistory(input);
        updateTurtles();
        return evaluate(root);
    }

    /**
     * Evaluates the expression tree, given the root
     * 
     * @param root
     *            the root of the expression tree
     * @return the double value which results from evaluating the expression
     *         tree
     */
    public double evaluate(Expression<Double> root)
    {
        return myModel.evaluateForActiveTurtles(root);
    }

    /**
     * Parses the string and returns the root of an expression tree which
     * represents the string
     * 
     * @param input
     *            the string to parse
     * @return the root of the expression tree
     */
    public Expression<Double> parse(String input)
    {
        return myModel.parseInput(input);
    }

    /**
     * Gets all the turtles. Used primarily by view to get the turtle's new
     * positions after they've been updated by the model
     * 
     * @return all of the turtles
     */
    public Collection<Turtle> getTurtles()
    {
        return myModel.getTurtles();
    }

    /**
     * The requisite observer method, which observes the turtles. Depending on
     * the action, decides what to do.
     */
    public void update(Observable thing, Object o)
    {
        Turtle t = ((actions.AbstractAction) o).turtle;

        if (o instanceof actions.MoveAction)
        {
            actions.MoveAction action = ((actions.MoveAction) o);
            myView.turtleMoved(t, action.oldX, action.oldY, action.newX,
                    action.newY);
        }
        else if (o instanceof actions.PropertyAction)
        {
            actions.PropertyAction action = ((actions.PropertyAction) o);
            t.update(action.newImage, action.newPen, action.visible);
            refreshView();
        }
    }

    /**
     * Used for text input bar. Is set as null in the beginning.
     */
    public void insertText(String s)
    {

    }

    public void setTextInput(TextInput textInput)
    {

    }

    /**
     * Adds the given input to the history
     * 
     * @param input
     */
    public void updateHistory(String input)
    {
        myHistory.updateList(input);
    }

    /**
     * Any commands which add new turtles or change turtle state should call
     * this method
     * 
     * @param input
     */
    public void updateTurtles()
    {
        myTurtles.replaceList(new ArrayList<Turtle>(getTurtles()));
    }

    public void setHistoryList(HistoryList list)
    {
        myHistory = list;
    }

    public void setTurtleList(TurtleList list)
    {
        myTurtles = list;
        updateTurtles();
    }

    public void clearScreen()
    {
        myView.clearScreen();
        myModel.resetTurtles();
    }

    public void tellTurtlesToPaintThemselves(Graphics2D graphics, AbstractCoordinateSystem coordinates)
    {
        myModel.tellTurtlesToPaintThemselves(graphics, coordinates);
    }

    /**
     * Refreshes the view. To be used for things like after the visibility of
     * the turtles has changed.
     */
    public void refreshView()
    {
        myView.repaint();
    }

    public void doAnimation()
    {
        myView.getCanvas().animate(true);
    }

    public void undoAnimation()
    {
        myView.getCanvas().animate(false);
    }

    public void zoomCamera(double zoomFactor)
    {
        myView.zoomCamera(zoomFactor);
        refreshView();
    }

    public void moveCamera(int left, int up)
    {
        myView.moveCamera(left, up);
        refreshView();
    }
}
